
/*
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "config.h"

#include <stdio.h>

#include "main.h"
#include "mpool.h"
#include "nes.h"
#include "options.h"

/* uniq number of node */
int nodenumber = 1;

struct dln *nl = NULL;
struct dln *wnl = NULL;
struct dle *el = NULL;
struct dle *wel = NULL;
struct usubg *sgl = NULL;
struct usubg *sglend = NULL;

static struct mpool *nl_pool;
static struct mpool *nl2_pool;
static struct mpool *el_pool;
static struct mpool *el2_pool;
static struct mpool *dln_pool;
static struct mpool *dln2_pool;
static struct mpool *dle_pool;
static struct mpool *dle2_pool;
static struct mpool *sg_pool;

void
unode_reset (void)
{

  nl = NULL;
  wnl = NULL;
  el = NULL;
  wel = NULL;
  sgl = NULL;
  sglend = NULL;

  mpool_pool_delete (nl_pool);
  nl_pool = mpool_pool_new ();

  mpool_pool_delete (nl2_pool);
  nl2_pool = mpool_pool_new ();

  mpool_pool_delete (el_pool);
  el_pool = mpool_pool_new ();

  mpool_pool_delete (el2_pool);
  el2_pool = mpool_pool_new ();

  mpool_pool_delete (dln_pool);
  dln_pool = mpool_pool_new ();

  mpool_pool_delete (dln2_pool);
  dln2_pool = mpool_pool_new ();

  mpool_pool_delete (dle_pool);
  dle_pool = mpool_pool_new ();

  mpool_pool_delete (dle2_pool);
  dle2_pool = mpool_pool_new ();

  return;
}

void
relayout (void)
{
  wnl = NULL;
  wel = NULL;

  mpool_pool_delete (dln2_pool);
  dln2_pool = mpool_pool_new ();

  mpool_pool_delete (dle2_pool);
  dle2_pool = mpool_pool_new ();

  mpool_pool_delete (el2_pool);
  el2_pool = mpool_pool_new ();

  mpool_pool_delete (nl2_pool);
  nl2_pool = mpool_pool_new ();

  return;
}

void
uedge_reset (void)
{
  return;
}

void
usubgraph_reset (void)
{
  mpool_pool_delete (sg_pool);
  sg_pool = mpool_pool_new ();
  sgl = NULL;
  sglend = NULL;
  return;
}

struct usubg *
usubg_new (char *name, struct usubg *rootedon)
{
  struct usubg *nsg;
  nsg = mpool_pool_malloc (sg_pool, sizeof (struct usubg));
  /* subgraph name ref */
  nsg->name = name;
  nsg->label = name;
  /* summary node is not linked in only part of usubg */
  nsg->summaryn = mpool_pool_malloc (sg_pool, sizeof (struct unode));
  /* unique number */
  nsg->summaryn->number = nodenumber;
  nodenumber = nodenumber + 1;
  /* summary node name */
  nsg->summaryn->name = name;
  /* summary node display label */
  nsg->summaryn->label = name;
  /* this is a subgraph summary node */
  nsg->summaryn->bitflags.sumnode = 1;
  /* summary node is rooted on subgraph or rootgraph */
  nsg->rootedon = rootedon;
  nsg->summaryn->rootedon = rootedon;
  /* summary node background color white */
  nsg->summaryn->color = 0x00ffffff;
  /* add to database of subgraphs */
  if (sglend)
    {
      sglend->next = nsg;
      sglend = nsg;
    }
  else
    {
      sgl = nsg;
      sglend = nsg;
    }
  return ((struct usubg *) nsg);
}

/* add subgraph to another subgraph */
void
usubg_add (struct usubg *subg, struct usubg *rootedon)
{
  struct dlsg *nsg = NULL;
  if (rootedon == NULL)
    {
      /* only in toplevel subgraph database added */
    }
  else
    {
      if (option_debug)
	{
	  printf ("%s(): appending subgraph %s to subgraph %s\n",
		  __FUNCTION__, subg->name, rootedon->name);
	}
      nsg = mpool_pool_malloc (sg_pool, sizeof (struct dlsg));
      nsg->sg = subg;
      if (rootedon->sgend)
	{
	  rootedon->sgend->next = nsg;
	  rootedon->sgend = nsg;
	}
      else
	{
	  rootedon->sg = nsg;
	  rootedon->sgend = nsg;
	}
    }
  return;
}

/* add node to subgraph */
void
usubg_add_node (struct unode *un, struct usubg *rootedon)
{
  struct dln *nn = NULL;
  if (0)
    {
      if (rootedon)
	{
	  printf ("adding node %s to subgraph %s\n", un->name,
		  rootedon->name);
	}
    }
  if (rootedon == NULL)
    {
      /* only in toplevel node database added */
    }
  else
    {
      nn = mpool_pool_malloc (sg_pool, sizeof (struct dln));
      nn->un = un;
      if (rootedon->nlend)
	{
	  rootedon->nlend->next = nn;
	  rootedon->nlend = nn;
	}
      else
	{
	  rootedon->nl = nn;
	  rootedon->nlend = nn;
	}
    }
  return;
}

/* add edge to subgraph */
void
usubg_add_edge (struct uedge *ue, struct usubg *rootedon)
{
  struct dle *ne = NULL;
  if (rootedon == NULL)
    {
      /* only in toplevel edge database added */
    }
  else
    {
      ne = mpool_pool_malloc (sg_pool, sizeof (struct dle));
      ne->ue = ue;
      if (rootedon->elend)
	{
	  rootedon->elend->next = ne;
	  rootedon->elend = ne;
	}
      else
	{
	  rootedon->el = ne;
	  rootedon->elend = ne;
	}
    }
  return;
}

struct unode *
unode_new (char *name)
{
  struct unode *un;
  un = mpool_pool_malloc (nl_pool, sizeof (struct unode));
  un->name = (char *)name;
  un->label = (char *)name;
  un->number = nodenumber;
  nodenumber = nodenumber + 1;
  un->color = 0x00ffffff;
  return ((struct unode *) un);
}

struct unode *
unode_new2 (char *name)
{
  struct unode *un;
  un = mpool_pool_malloc (nl2_pool, sizeof (struct unode));
  un->name = name;
  un->label = name;
  un->number = nodenumber;
  nodenumber = nodenumber + 1;
  un->color = 0x00ffffff;
  return ((struct unode *) un);
}

struct uedge *
uedge_new (struct unode *fn, struct unode *tn)
{
  struct uedge *ue;
  ue = mpool_pool_malloc (el_pool, sizeof (struct uedge));
  ue->fn = fn;
  ue->tn = tn;
  ue->color = 0;		/* black line */
  ue->style = 0;		/* solid line */
  return ((struct uedge *) ue);
}


struct uedge *
uedge_new2 (struct unode *fn, struct unode *tn)
{
  struct uedge *ue;
  ue = mpool_pool_malloc (el2_pool, sizeof (struct uedge));
  ue->fn = fn;
  ue->tn = tn;
  ue->color = 0;		/* black line */
  ue->style = 0;		/* solid line */
  return ((struct uedge *) ue);
}


void
unode_append_nodelist (struct unode *un)
{
  struct dln *dn;
  struct dln *pdn;
  dn = dln_new (un);
  if (nl == (struct dln *) 0)
    {
      nl = dn;
      nl->next = (struct dln *) 0;
      nl->prev = (struct dln *) 0;
      return;
    }
  pdn = nl;
  while (pdn)
    {
      if (pdn->next == (struct dln *) 0)
	{
	  break;
	}
      pdn = pdn->next;
    }
  pdn->next = dn;
  dn->prev = pdn;
  dn->next = (struct dln *) 0;
  return;
}

void
uedge_append_edgelist (struct uedge *ue)
{
  struct dle *edn;
  struct dle *pde;
  edn = dle_new (ue);
  if (el == (struct dle *) 0)
    {
      el = edn;
      el->prev = (struct dle *) 0;
      el->next = (struct dle *) 0;
      return;
    }
  pde = el;
  while (pde)
    {
      if (pde->next == (struct dle *) 0)
	{
	  break;
	}
      pde = pde->next;
    }
  pde->next = edn;
  edn->prev = pde;
  edn->next = (struct dle *) 0;
  return;
}

void
append_wnl (struct dln *dn)
{
  struct dln *pdn = NULL;
  /* node is in working node list */
  dn->un->bitflags.inwnl = 1;
  if (wnl == (struct dln *) 0)
    {
      wnl = dn;
      wnl->next = (struct dln *) 0;
      wnl->prev = (struct dln *) 0;
      return;
    }
  pdn = wnl;
  while (pdn)
    {
      if (pdn->next == (struct dln *) 0)
	{
	  break;
	}
      pdn = pdn->next;
    }
  pdn->next = dn;
  dn->prev = pdn;
  dn->next = (struct dln *) 0;
  return;
}

void
append_wel (struct dle *edn)
{
  struct dle *pde;
  /* edge is in working edge list */
  edn->ue->bitflags.inwel = 1;
  if (wel == (struct dle *) 0)
    {
      wel = edn;
      wel->prev = (struct dle *) 0;
      wel->next = (struct dle *) 0;
      return;
    }
  pde = wel;
  while (pde)
    {
      if (pde->next == (struct dle *) 0)
	{
	  break;
	}
      pde = pde->next;
    }
  pde->next = edn;
  edn->prev = pde;
  edn->next = (struct dle *) 0;
  return;
}


struct dln *
dln_new (struct unode *un)
{
  struct dln *dn;
  dn = mpool_pool_malloc (dln_pool, sizeof (struct dln));
  dn->un = un;
  return ((struct dln *) dn);
}

struct dln *
dln_new2 (struct unode *un)
{
  struct dln *dn;
  dn = mpool_pool_malloc (dln2_pool, sizeof (struct dln));
  dn->un = un;
  return ((struct dln *) dn);
}



struct dle *
dle_new (struct uedge *ue)
{
  struct dle *de;
  de = mpool_pool_malloc (dle_pool, sizeof (struct dle));
  de->ue = ue;
  return ((struct dle *) de);
}


struct dle *
dle_new2 (struct uedge *ue)
{
  struct dle *de;
  de = mpool_pool_malloc (dle2_pool, sizeof (struct dle));
  de->ue = ue;
  return ((struct dle *) de);
}

void
hasinout (void)
{
  struct dln *ptr;
  struct dle *ptre;
  ptr = wnl;
  while (ptr)
    {
      ptr->un->bitflags.hasin = 0;
      ptr->un->bitflags.hasout = 0;
      ptr = ptr->next;
    }
  ptre = wel;
  while (ptre)
    {
      /* outgoing edge for the from-node */
      ptre->ue->fn->bitflags.hasout = 1;
      /* incoming edge for the to-node */
      ptre->ue->tn->bitflags.hasin = 1;
      ptre = ptre->next;
    }
  return;
}

void
singlenodes (void)
{
  struct dln *ptr;
  struct dle *ptre;
  struct usubg *sgp;
  int val = 0;
  ptr = nl;
  while (ptr)
    {
      ptr->un->bitflags.hasin = 0;
      ptr->un->bitflags.hasout = 0;
      ptr->un->bitflags.singlenode = 0;
      ptr = ptr->next;
    }
  ptre = el;
  while (ptre)
    {
      /* outgoing edge for the from-node */
      ptre->ue->fn->bitflags.hasout = 1;
      /* incoming edge for the to-node */
      ptre->ue->tn->bitflags.hasin = 1;
      ptre = ptre->next;
    }
  ptr = nl;
  while (ptr)
    {
      if (ptr->un->bitflags.hasin == 0 && ptr->un->bitflags.hasout == 0)
	{
	  ptr->un->bitflags.singlenode = 1;
	}
      /* do not mark subgraph summary nodes as unconnected single node */
      if (ptr->un->bitflags.sumnode)
	{
	  ptr->un->bitflags.singlenode = 0;
	}
      /* do not mark parse error message node as single node */
      if (ptr->un->bitflags.parseerror)
	{
	  ptr->un->bitflags.singlenode = 0;
	}
      ptr = ptr->next;
    }
  ptre = el;
  while (ptre)
    {
      if (ptre->ue->fn->rootedon && ptre->ue->tn->rootedon)
	{
	  /* edge is inside one subgraph */
	  if (ptre->ue->fn->rootedon == ptre->ue->tn->rootedon)
	    {
	      ptre->ue->bitflags.inedge = 1;
	    }
	  else
	    {
	      /* edge crosses subgraphs */
	      ptre->ue->bitflags.inedge = 0;
	    }
	}
      ptre = ptre->next;
    }
  /* optional configure initial folding of subgraphs */
  if (settings_init_folded)
    {
      if (settings_init_folded == 2)
	{
	  val = 1;
	}
      else
	{
	  val = 0;
	}
      sgp = sgl;
      while (sgp)
	{
	  sgp->bitflags.folded = val;
	  sgp = sgp->next;
	}
    }
  return;
}

/* End. */
